package com.zzyl.intercept;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import com.zzyl.utils.ThreadLocalUtil;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @Intercepts：mybatis的拦截器
 * @Signature：指明该拦截器需要拦截哪个接口的哪一个方法，type接口类，method方法名称，args方法参数类型
 */
@Component
@Intercepts(
		@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
)
public class AutoFillInterceptor implements Interceptor {
	
	private static final String CREATE_BY = "createBy";
	private static final String UPDATE_BY = "updateBy";
	
	private static final String CREATE_TIME = "createTime";
	private static final String UPDATE_TIME = "updateTime";
	
	//进行拦截的时候要执行的方法
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		// 获取描述SQL语句的映射信息
		MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
		// 获取sql参数实体 ParamMap
		Object parameter = invocation.getArgs()[1];
		
		//获取SQL的类型，INSERT？UPDATE？
		SqlCommandType sqlCommandType = ms.getSqlCommandType();
		
		if (ObjectUtil.isEmpty(parameter) || ObjectUtil.isEmpty(sqlCommandType)) {
			return invocation.proceed();// 继续执行原始方法
		}
		
		// 获取用户ID
		Long userId = ThreadLocalUtil.get();
		
		if (ObjectUtil.equals(SqlCommandType.INSERT, sqlCommandType)) {
			// 插入操作
			if (parameter instanceof MapperMethod.ParamMap) {
				// 批量插入的情况
				MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) parameter;
				List list = (List) paramMap.get("list");
				list.forEach(val -> {
					// 设置创建人和创建时间字段值
					setFieldValByName(CREATE_BY, userId, val);
					setFieldValByName(UPDATE_BY, userId, val);
					
					setFieldValByName(CREATE_TIME, LocalDateTime.now(), val);
					setFieldValByName(UPDATE_TIME, LocalDateTime.now(), val);
				});
				paramMap.put("list", list);
			} else {
				// 单条插入的情况：设置创建人和创建时间字段值
				setFieldValByName(CREATE_BY, userId, parameter);
				setFieldValByName(UPDATE_BY, userId, parameter);
				
				setFieldValByName(CREATE_TIME, LocalDateTime.now(), parameter);
				setFieldValByName(UPDATE_TIME, LocalDateTime.now(), parameter);
			}
		} else if (ObjectUtil.equals(SqlCommandType.UPDATE, sqlCommandType)) {
			// 更新操作：设置更新人和更新时间字段值
			setFieldValByName(UPDATE_BY, userId, parameter);
			setFieldValByName(UPDATE_TIME, LocalDateTime.now(), parameter);
		}
		// 继续执行原始方法
		return invocation.proceed();
	}
	
	/**
	 * 通过反射设置实体的字段值
	 * @param fieldName 字段名
	 * @param fieldVal  字段值
	 * @param parameter 实体对象
	 */
	private void setFieldValByName(String fieldName, Object fieldVal, Object parameter) {
		//如果属性有只值，就忽略
		Object fieldValue = ReflectUtil.getFieldValue(parameter, fieldName);
		if (ObjectUtil.isNotEmpty(fieldValue)) {
			return;
		}
		
		//通过反射，给 parameter 对象的 fieldName 属性 赋值 fieldVal
		if (ReflectUtil.hasField(parameter.getClass(), fieldName)) {
			ReflectUtil.setFieldValue(parameter, fieldName, fieldVal);
		}
	}
	
	@Override
	public Object plugin(Object target) {
		if (target instanceof Executor) {
			// 对目标对象进行包装，返回代理对象
			return Plugin.wrap(target, this);
		}
		// 非 Executor 类型的对象，直接返回原始对象
		return target;
	}
}

